package com.example.controller;

import com.alibaba.druid.util.StringUtils;
import com.example.annotations.RequiredToken;
import com.example.entity.Favorite;
import com.example.entity.Played;
import com.example.entity.User;
import com.example.entity.Video;
import com.example.feignclients.VideosClient;
import com.example.service.FavoriteService;
import com.example.service.PlayedService;
import com.example.service.UserService;
import com.example.utils.ImageUtils;
import com.example.utils.JSONUtils;
import com.example.utils.OSSUtils;
import com.example.utils.RedisPrefix;
import com.example.vo.MsgVO;
import com.example.vo.VideoVO;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 用户(User)表控制层
 *
 * @author makejava
 * @since 2022-03-03 10:19:16
 */
@RestController
@RequestMapping("user")
@Slf4j
public class UserController {
    /**
     * 服务对象
     */
    @Resource
    private UserService userService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private VideosClient videosClient;
    @Autowired
    private PlayedService playedService;
    @Autowired
    private FavoriteService favoriteService;


    /**
     * 收藏列表
     * @param page
     * @param rows
     * @param request
     * @return
     */
    @GetMapping("/user/favorites")
    public List<VideoVO> favorites(@RequestParam("page") Integer page,@RequestParam("per_page") Integer rows,HttpServletRequest request){
        User user = (User) request.getAttribute("user");
        List<VideoVO> videoVOS=favoriteService.findFavoritesByUserId(user.getId(),page,rows);
        log.info("当前用户收藏的视频是{}",videoVOS);
        return videoVOS;

    }
    /**
     * 视频播放历史
     * @param page
     * @param rows
     * @param request
     * @return
     */
    @GetMapping("/user/played")
    @RequiredToken
    public List<VideoVO> playedHistory(@RequestParam("page") Integer page,@RequestParam("per_page") Integer rows,HttpServletRequest request){
        User user = (User) request.getAttribute("user");
        List<VideoVO> videoVOS=playedService.queryByUserId(user.getId(),page,rows);
        log.info("当前用户播放历史的视频为{}",JSONUtils.writeValueAsString(videoVOS));
        return videoVOS;

    }
    /**
     * 用户取消收藏
     * @param videoId
     * @param request
     */
    @DeleteMapping("/user/favourites/{id}")
    public void cancelFavourite(@PathVariable("id") String videoId,HttpServletRequest request){
        User user = (User) request.getAttribute("user");
        log.info("取消的收藏视频id{}",videoId);
        int i=favoriteService.cancelByVideoIdAndUserId(videoId,user.getId());
        log.info("取消收藏成功{}",i>0);
    }

    /**
     * 视频收藏
     * @param videoId
     * @param request
     */
    @PutMapping("/user/favourites/{id}")
    @RequiredToken
    public void favourite(@PathVariable("id") Integer videoId,HttpServletRequest request){
        //获取当前用户信息
        User user = (User) request.getAttribute("user");
        //判断是否收藏该视频
        Favorite favorite =favoriteService.queryByvideoIdAndUserId(videoId,user.getId());
        if (ObjectUtils.isEmpty(favorite)){
            favorite = new Favorite();
            favorite.setUid(user.getId());
            favorite.setVideoId(videoId);
            favoriteService.insert(favorite);
            log.info("收藏视频=={}成功",JSONUtils.writeValueAsString(favorite));
        }
    }

    /**
     * 用户取消不喜欢该视频
     * @param videoId
     * @param request
     */
    @DeleteMapping("/user/disliked/{id}")
    @RequiredToken
    public void cancelDisliked(@PathVariable("id") String videoId,HttpServletRequest request){
        User user = (User) request.getAttribute("user");
        //将当前视频从用户的不喜欢中移除
        if (stringRedisTemplate.opsForSet().isMember(RedisPrefix.USER_DISLIKE_PREFIX+user.getId(),videoId)){
            stringRedisTemplate.opsForSet().remove(RedisPrefix.USER_DISLIKE_PREFIX+user.getId(),videoId);
        }
    }

    /**
     * 用户点击不喜欢该视频
     * @param videoId
     * @param request
     */
    @PutMapping("/user/disliked/{id}")
    @RequiredToken
    public void disliked(@PathVariable("id") String videoId,HttpServletRequest request){
        //获取当前的用户信息
        User user = (User) request.getAttribute("user");
        log.info("接受到的视频id{}",videoId);
        //将该视频id放入到用户的不喜欢列表中
        stringRedisTemplate.opsForSet().add(RedisPrefix.USER_DISLIKE_PREFIX+user.getId(),videoId);
        //判断之前是否喜欢过该视频
        if (stringRedisTemplate.opsForSet().isMember(RedisPrefix.USER_LIKE_PREFIX+user.getId(),videoId)){
            //从喜欢的列表中移除
            stringRedisTemplate.opsForSet().remove(RedisPrefix.USER_LIKE_PREFIX+user.getId(),videoId);
            //喜欢的次数-1
            stringRedisTemplate.opsForValue().decrement(RedisPrefix.VIDEO_LIKE_COUNT_PREFIX+videoId);
        }
    }

    /**
     * 用户取消点赞视频
     * @param videoId
     * @param request
     */
    @DeleteMapping("/user/liked/{id}")
    @RequiredToken
    public void cancelLiked(@PathVariable("id") String videoId,HttpServletRequest request){
        //获取用户信息
        User user = (User) request.getAttribute("user");
        log.info("接受到的视频id{}",videoId);
        //将当前用户喜欢的列表视频id移除掉
        stringRedisTemplate.opsForSet().remove(RedisPrefix.USER_LIKE_PREFIX+user.getId(),videoId);
        //将视频的点赞次数-1
        stringRedisTemplate.opsForValue().decrement(RedisPrefix.VIDEO_LIKE_COUNT_PREFIX+videoId);

    }

    /**
     * 用户点赞视频
     * @param videoId
     * @param request
     */
    @PutMapping("/user/liked/{id}")
    @RequiredToken
    public void liked(@PathVariable("id") String videoId, HttpServletRequest request){
        //获取当前用户的登录信息
        User user = (User) request.getAttribute("user");
        log.info("接受到的视频id：{}",videoId);
        //将视频点赞次数＋1
        stringRedisTemplate.opsForValue().increment(RedisPrefix.VIDEO_LIKE_COUNT_PREFIX+videoId);
        //将当前用户点赞列表放入redis中
        stringRedisTemplate.opsForSet().add(RedisPrefix.USER_LIKE_PREFIX+user.getId(),videoId);
        //将不喜欢列表中视频删除
        if (stringRedisTemplate.opsForSet().isMember(RedisPrefix.USER_DISLIKE_PREFIX+user.getId(),videoId)){
            stringRedisTemplate.opsForSet().remove(RedisPrefix.USER_DISLIKE_PREFIX+user.getId(),videoId);
        }

    }


    /**
     * 根据请求参数获取token中的user信息
     * @param request
     * @return
     */
    private User getUser(HttpServletRequest request){
        String token = request.getParameter("token");
        log.info("获取的token{}",token);
        String tokenKey= "session_"+token;
        User user = (User) redisTemplate.opsForValue().get(tokenKey);
        return user;
    }

    /**
     * 视频播放
     * @param id
     * @param request
     */
    @PutMapping("/user/played/{id}")
    public void played(@PathVariable String id,HttpServletRequest request){
        //redis中播放次数＋1
        stringRedisTemplate.opsForValue().increment(RedisPrefix.VIDEO_PLAYED_COUNT_PREFIX+id,1);
        //获取用户信息
        User user = getUser(request);
        if (!ObjectUtils.isEmpty(user)){
            Played played = new Played();
            played.setUid(user.getId());
            played.setVideoId(Integer.valueOf(id));
            playedService.insert(played);
            log.info("当前用户播放记录保存信息成功，信息为{}", JSONUtils.writeValueAsString(played));
        }
    }

    @PostMapping("/user/videos")
    @RequiredToken
    public Video publishVideo(MultipartFile file,Video video,Integer category_id,HttpServletRequest request) throws IOException {
        //获取文件原始名称
        String originalFilename = file.getOriginalFilename();
        log.info("接受文件名称：{}",originalFilename);
        log.info("接收到的视频信息：{}",new ObjectMapper().writeValueAsString(video));
        log.info("类别id：{}",category_id);
        log.info("文件大小：{}",file.getSize());
        //获取文件后缀名  mp4 avi
        String ext = FilenameUtils.getExtension(originalFilename);
        //生成uuid
        String uuidFileName = UUID.randomUUID().toString().replace("-", "");
        //生成uuid文件名
        String newFilename=uuidFileName +"."+ ext;
        //上传至阿里云oss，返回文件在oss地址
        String url = OSSUtils.upload(file.getInputStream(), "videos", newFilename);
        log.info("上传成功之后的返回地址：{}",url);
        //阿里云oss截取视频中某一帧作为封面
        String cover = url + "?x-oss-process=video/snapshot,t_30000,f_jpg,w_0,h_0,m_fast,ar_auto";
        log.info("阿里云oss根据url截取视频封面: {}", cover);
        //设置视频信息
        video.setCover(cover); //设置视频封面
        video.setLink(url); //设置视频地址
        video.setCategoryId(category_id); //设置视频类别
        //获取用户信息
        User user = (User) request.getAttribute("user");
        video.setUid(user.getId());
        //调用视频服务
        Video videoResult = videosClient.publish(video);
        log.info("视频发布之后成功返回的视频信息：{}",new ObjectMapper().writeValueAsString(videoResult));
        return videoResult;

    }

    /** Redis中
     *  phone_key 对应的是验证码
     * @param user
     * @param request
     * @return
     */
    @PatchMapping("/user")
    @RequiredToken
    public User user(@RequestBody User user,HttpServletRequest request){
        //获取token
        String token = (String) request.getAttribute("token");
        // 获取原始用户的信息
        User userOld = (User) request.getAttribute("user");
        //是否修改手机号码
        if (!ObjectUtils.isEmpty(user.getPhone())){
            //修改手机号
            String phoneKey= "phone_"+user.getPhone();
            if (!stringRedisTemplate.hasKey(phoneKey)){
                throw new RuntimeException("提示：验证码已经获取");
            }
            //获取redis里面存的验证码
            String RedisCaptcha = stringRedisTemplate.opsForValue().get(phoneKey);
            if (!StringUtils.equals(RedisCaptcha,user.getCaptcha())){
                throw new RuntimeException("提示：验证码不正确");
            }
            userOld.setPhone(user.getPhone());
        }
        //未修改手机号
        if (!StringUtils.isEmpty(user.getName())){
            userOld.setName(user.getName());
        }
        if (StringUtils.isEmpty(user.getIntro())){
            userOld.setIntro(user.getIntro());
        }
        //更新数据库用户信息
        userService.insert(userOld);
        //更新redis中的用户信息
        redisTemplate.opsForValue().set("session_"+token,userOld,7,TimeUnit.DAYS);
        return userOld;
    }

    /**
     * 已登录的用户信息
     * @param request
     * @return
     * @throws JsonProcessingException
     */
    @RequiredToken
    @GetMapping("/user")
    public User user(HttpServletRequest request) throws JsonProcessingException {
        User user = (User) request.getAttribute("user");
        log.info("登录的用户信息是{}",new ObjectMapper().writeValueAsString(user));
        return user;
    }

    //用户注销
    @DeleteMapping("/tokens")
    public void logout(String token){
        log.info("获取当前的token信息{}",token);
        //1.根据token拼接对应的tokenKey
        String tokenKey= "session_"+token;
        //2.根据TokenKey在redis里面删除
        stringRedisTemplate.delete(tokenKey);


    }

    //用户登录
    @PostMapping("/tokens")
    public Map<String, Object> tokens(@RequestBody MsgVO msgVO, HttpServletRequest request){
        Map<String, Object> result = new HashMap<>();
        //获取输入的手机号码
        String phone = msgVO.getPhone();
        //获取用户验证码
        String captcha = msgVO.getCaptcha();
        log.info("手机号码是{}，验证码是{}",phone,captcha);
        String phoneKey="phone_"+phone;
        //根据用户输入的手机号去判断redis中该验证码是否失效
        if (!stringRedisTemplate.hasKey(phoneKey)){
            throw new RuntimeException("提示：验证码已经过期");
        }
        //根据手机号获取redis中的验证码
        String redisCaptcha = stringRedisTemplate.opsForValue().get(phoneKey);
        //比较用户输入的验证码和redis中存储的是否一致
        if (!StringUtils.equals(captcha,redisCaptcha)) throw new RuntimeException("提示：验证码错误！");
        //判断用户是否首次登录
        User user = userService.findByPhone(phone);
        if (ObjectUtils.isEmpty(user)){

            user = new User();
            user.setCreatedAt(new Date());
            user.setUpdatedAt(new Date());
            user.setPhone(phone);
            user.setName(phone);
            user.setIntro("");
            //随机初始化头像
            user.setAvatar(ImageUtils.getPhoto());
            user.setPhoneLinked(1);//是否绑定手机
            user.setWechatLinked(0);//是否绑定微信
            user.setFollowersCount(0);//设置粉丝数
            user.setFollowingCount(0);//设置关注数
            userService.insert(user); //保存用户信息
        }
        //保存用户信息
        String token = request.getSession().getId();
        String tokenKey= "session_"+token;
        log.info("生成的token=={}",token);
        //redisTemplate 操作对象  key:对象  value:对象  注意:必须实现对象序列化接口  jdk序列化方式
        //redisTemplate对象中默认序列化方式进行修改: key:String序列化方式   value:json序列化
        redisTemplate.opsForValue().set(tokenKey,user,7, TimeUnit.DAYS);
        //返回token
        result.put("token",token);
        return result;
    }


}

